import { _decorator, CircleCollider2D, color, Component, EventTouch, HingeJoint2D, Input, Intersection2D, Node, PhysicsSystem2D, PolygonCollider2D, RigidBody2D, tween, UIOpacity, UITransform, v2, v3, Vec2, Vec3 } from 'cc';
import { EffMgr } from '../manager/EffMgr';
import { ENUM_AUDIO_CLIP } from '../Enum';
import { Block } from './Block';
import { getDis, getRand } from '../Util';
import { PoolMgr } from '../manager/PoolMgr';
import { AudioMgr } from '../manager/AudioMgr';
import { DataMgr } from '../manager/DataMgr';
import { Ins } from '../Ins';
const { ccclass, property } = _decorator;

enum ENUM_SCREW_STATUS {
    IN = 'in',
    OUT = 'out',
    MOVE = 'move'
}

enum ENUM_RG_GROUP {
    DEFAULT = 0,
    SCIN = 1
}

const DIS_TARGET = 15
const DIS_CORE = 5
const SCOUT_OY = 80
const CORE_MAX = 65
const CORE_MIN = 10
const SPEED_LIN = 1
const SPEED_ANG = 0.5

@ccclass('Game')
export class Game extends Component {
    targets_node: Node = null
    blocks_node: Node = null
    screws_node: Node = null
    current_in: Node = null
    current_out: Node = null
    status: ENUM_SCREW_STATUS = ENUM_SCREW_STATUS.IN

    init() {
        const board = this.node.getChildByName('scboard')
        this.targets_node = board.getChildByName('targets')
        this.blocks_node = board.getChildByName('blocks')
        this.screws_node = board.getChildByName('screws')
        for (let i = 0; i < this.blocks_node.children.length; i++) {
            const block = this.blocks_node.children[i]
            const blockComp = block.getComponent(Block)
            const corePosArr = blockComp.getCorePosArr()
            // 生成target
            for (let j = 0; j < corePosArr.length; j++) {
                const corePos = corePosArr[j]
                const targetPos = this.targets_node.getComponent(UITransform).convertToNodeSpaceAR(corePos)
                if (!this.isTargetInter(targetPos)) PoolMgr.ins.getNode('Target', this.targets_node, targetPos)
            }
        }

        if (!board.hasEventListener(Input.EventType.TOUCH_START)) {
            board.on(Input.EventType.TOUCH_START, this.onTouch, this)
        }
        DataMgr.ins.total = this.blocks_node.children.length
    }

    // target 相交情况
    isTargetInter(pos: Vec3) {
        let bool = false
        for (let i = 0; i < this.targets_node.children.length; i++) {
            const target = this.targets_node.children[i]
            const targetPos = target.getPosition()
            const distance = getDis(pos, targetPos)
            if (distance <= DIS_TARGET) {
                bool = true
                break
            }
        }
        return bool
    }

    onTouch(e: EventTouch) {
        if (this.status == ENUM_SCREW_STATUS.MOVE) return
        const loc = e.touch.getUILocation()
        const touchPoint = this.node.getComponent(UITransform).convertToNodeSpaceAR(v3(loc.x, loc.y, 0))
        if (Ins.UIMgr.getMainSkillTip()) {
            if (this.current_out) {
                this.setActive(false)
            } else {
                const scin = this.getScin(loc)
                if (scin) {
                    AudioMgr.ins.playSound(ENUM_AUDIO_CLIP.SKILL_REMOVE)
                    Ins.UIMgr.toggleMainSkillTip(false)
                    scin.destroy()
                } else {
                    AudioMgr.ins.playSound(ENUM_AUDIO_CLIP.UNCLICK)
                    EffMgr.ins.show('EffTouch', this.node, touchPoint)
                }
            }
            return
        }
        if (!this.current_in) {
            const scin = this.getScin(loc)
            if (scin) {
                this.setActive(true, scin)
            } else {
                AudioMgr.ins.playSound(ENUM_AUDIO_CLIP.UNCLICK)
                EffMgr.ins.show('EffTouch', this.node, touchPoint)
            }
        } else {
            const scin = this.getScin(loc)
            if (!scin) {
                // 找螺丝孔
                const target = this.getTarget(loc)
                if (!target) {
                    this.setActive(false)
                } else {
                    const targetTransform = target.getComponent(UITransform)
                    const targetPos = targetTransform.convertToWorldSpaceAR(v3(0, 0, 0))
                    const targetRadius = target.getComponent(CircleCollider2D).radius
                    const targetRect = targetTransform.getBoundingBoxToWorld()
                    let isInter = false, isCover = false, cores = []
                    for (let i = 0; i < this.blocks_node.children.length; i++) {
                        const block = this.blocks_node.children[i]
                        const targetPoint = block.getComponent(UITransform).convertToNodeSpaceAR(targetPos)
                        const points = block.getComponent(PolygonCollider2D).points
                        const inter = Intersection2D.polygonCircle(points, v2(targetPoint.x, targetPoint.y), targetRadius)
                        // console.log('孔与金属板相交', inter)
                        if (inter) {
                            isInter = true
                            for (let j = 0; j < block.children.length; j++) {
                                const core = block.children[j]
                                const coreTransform = core.getComponent(UITransform)
                                const corePos = coreTransform.convertToWorldSpaceAR(v3(0, 0, 0))
                                const coreRect = coreTransform.getBoundingBoxToWorld()
                                const isInter2 = coreRect.intersects(targetRect)
                                // console.log('孔与金属板开孔相交')
                                if (isInter2) {
                                    const dis = getDis(corePos, targetPos)
                                    // console.log('孔与金属板开孔交叉距离', dis)
                                    if (dis > CORE_MAX) {
                                        continue
                                    } else {
                                        if (dis <= CORE_MIN) {
                                            cores.push(core)
                                        } else {
                                            isCover = true
                                            break
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (isCover) cores = []
                    if (isInter) {
                        if (cores.length <= 0) {
                            EffMgr.ins.showTip('EffTip', '孔位被挡住了')
                            this.setActive(false)
                            return
                        }
                    }

                    // 开始移动
                    const { x, y, z } = target.getPosition()
                    this.status = ENUM_SCREW_STATUS.MOVE
                    tween(this.current_out).to(0.5, { position: v3(x, y + SCOUT_OY, z) }).call(() => {
                        if (cores.length <= 0) {
                            this.setMove(target)
                        } else {
                            this.setMove(target, cores)
                        }
                    }).start()
                }
            } else {
                // 是否切换螺丝
                if (this.current_in == scin) {
                    this.setActive(false)
                } else {
                    this.setActive(false)
                    this.setActive(true, scin)
                }
            }
        }
    }

    // 寻找螺丝
    getScin(pos: Vec2) {
        let scin = null
        for (let i = 0; i < this.screws_node.children.length; i++) {
            const sc = this.screws_node.children[i]
            if (sc.name == 'Scin') {
                const box = sc.getComponent(UITransform).getBoundingBoxToWorld()
                if (box.contains(pos)) {
                    scin = sc
                    break
                }
            }
        }
        return scin
    }

    // 切换螺丝转态
    setActive(bool: boolean = true, current: Node = null) {
        if (!bool) {
            if (this.current_in) {
                AudioMgr.ins.playSound(ENUM_AUDIO_CLIP.SCIN)
                this.status = ENUM_SCREW_STATUS.IN
                this.current_in.getComponent(UIOpacity).opacity = 255
                this.current_in = null
                this.current_out.removeFromParent()
                this.current_out = null
            }
        } else {
            this.current_in = current
            if (this.current_in) {
                AudioMgr.ins.playSound(ENUM_AUDIO_CLIP.SCOUT)
                this.status = ENUM_SCREW_STATUS.OUT
                if (this.current_in && this.current_in.getComponent(UIOpacity)) this.current_in.getComponent(UIOpacity).opacity = 0
                const { x, y } = this.current_in.getPosition()
                let nx = x, ny = y + SCOUT_OY
                this.current_out = PoolMgr.ins.getNode('Scout', this.screws_node, v3(nx, ny, 0))
            }
        }
    }

    // 找孔
    getTarget(pos: Vec2) {
        let node = null
        for (let i = 0; i < this.targets_node.children.length; i++) {
            const target = this.targets_node.children[i]
            const box = target.getComponent(UITransform).getBoundingBoxToWorld()
            if (box.contains(pos)) {
                node = target
                break
            }
        }
        if (node) {
            const nodeBox = node.getComponent(UITransform).getBoundingBoxToWorld()
            for (let i = 0; i < this.screws_node.children.length; i++) {
                const sc = this.screws_node.children[i]
                if (sc.name == 'Scin') {
                    const scBox = sc.getComponent(UITransform).getBoundingBoxToWorld()
                    if (Intersection2D.rectRect(nodeBox, scBox)) {
                        node = null
                        break
                    }
                }
            }
        }
        return node
    }

    // 移动
    setMove(target: Node, cores: Node[] = []) {
        AudioMgr.ins.playSound(ENUM_AUDIO_CLIP.SCIN)
        this.current_in?.destroy()
        this.current_out?.removeFromParent()
        this.current_in = null
        this.current_out = null
        const { x, y, z } = target.getPosition()
        const scin = PoolMgr.ins.getNode('Scin', this.screws_node, v3(x, y, z))
        if (cores.length <= 0) {
            this.setSpeed()
            this.status = ENUM_SCREW_STATUS.IN
        } else {
            for (let i = 0; i < cores.length; i++) {
                const core = cores[i]
                const coreTransform = core.getComponent(UITransform)
                const corePos = coreTransform.convertToWorldSpaceAR(v3(0, 0, 0))
                const block = core.parent
                const blockHingeArr = block.getComponents(HingeJoint2D)
                const pos = block.getComponent(UITransform).convertToNodeSpaceAR(corePos)
                let currentHinge: HingeJoint2D = null
                for (let j = 0; j < blockHingeArr.length; j++) {
                    const hinge = blockHingeArr[j]
                    const distance = getDis(pos, hinge.anchor)
                    if (distance <= DIS_CORE) {
                        currentHinge = hinge
                        break
                    }
                }
                if (currentHinge) {
                    currentHinge.enabled = false
                    currentHinge.connectedBody = scin.getComponent(RigidBody2D)
                    currentHinge.enabled = true
                    this.setSpeed()
                    this.status = ENUM_SCREW_STATUS.IN
                }
            }
        }
    }

    // 速度
    setSpeed() {
        for (let i = 0; i < this.blocks_node.children.length; i++) {
            const block = this.blocks_node.children[i]
            const rb = block.getComponent(RigidBody2D)
            const hinges = block.getComponents(HingeJoint2D)
            let hingeConnectNum = 0
            for (let j = 0; j < hinges.length; j++) {
                if (hinges[j].connectedBody?.node?.active) hingeConnectNum += 1
            }
            if (hingeConnectNum == 0) {
                // 水平速度
                const x = rb.linearVelocity.x
                if (Math.abs(x) >= 0.05) return
                let speed = SPEED_LIN
                if (x > 0) {
                    speed *= 1
                } else if (x < 0) {
                    speed *= -1
                } else {
                    const rand = getRand(0, 1)
                    if (rand) speed *= -1
                }
                this.scheduleOnce(() => {
                    rb.linearVelocity = v2(speed, 0)
                })
            } else if (hingeConnectNum == 1) {
                // 旋转速度
                const v = rb.angularVelocity
                if (Math.abs(v) >= 0.1) return
                let speed = SPEED_ANG
                if (v > 0) {
                    speed *= 1
                } else if (v < 0) {
                    speed *= -1
                } else {
                    const rand = getRand(0, 1)
                    if (rand) speed *= -1
                }
                this.scheduleOnce(() => {
                    rb.angularDamping = 0.2
                    rb.angularVelocity = speed
                })
            }
        }
    }
}


